Skip to content

fix(lsp): allow plugins to override document and root uri handling#1999

Merged
bajrangCoder merged 1 commit intoAcode-Foundation:mainfrom
bajrangCoder:lsp-plugin-uri-overrides
Mar 31, 2026
Merged

fix(lsp): allow plugins to override document and root uri handling#1999
bajrangCoder merged 1 commit intoAcode-Foundation:mainfrom
bajrangCoder:lsp-plugin-uri-overrides

Conversation

@bajrangCoder
Copy link
Copy Markdown
Member

Fixes: #1996

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 31, 2026

Greptile Summary

This PR allows LSP plugin authors to override both document URI and root URI resolution by adding a new documentUri hook to LspServerDefinition/LspServerManifest. It also fixes a long-standing priority bug where a caller-supplied context.rootUri would always short-circuit any server-specific rootUri function.

Key changes:

  • New documentUri hook: Plugins can now return a custom document URI via server.documentUri(originalUri, context). The hook receives the original URI and the auto-normalized URI.
  • Per-server URI resolution: #resolveDocumentUri is now called inside the server loop, so different servers attached to the same file can resolve to different URIs.
  • URI alias map: When originalUri !== normalizedUri, the original URI is registered as an alias in a new uriAliases map inside ClientState, ensuring external detach(originalUri) calls correctly reach the right fileRefs entry.
  • #resolveRootUri priority fix: server.rootUri function is now evaluated before context.rootUri, fixing Codemirror LSP not using uri I passed #1996.
  • Async-capable hooks: Both rootUri and documentUri now accept MaybePromise return values.

The formatDocument path calls state.attach(normalizedUri, view) without aliases (unlike getExtensionsForFile), leaving a pre-existing gap now inconsistent with the new alias mechanism.

Confidence Score: 5/5

Safe to merge — core logic is well-structured, all findings are P2 style/consistency suggestions, and no regressions are introduced.

All three comments are P2: one notes a pre-existing inconsistency in formatDocument (not a regression), one suggests exporting MaybePromise, and one flags the intentional #resolveRootUri priority change as worth documenting. None represent a current defect on the primary attach/detach path exercised by getExtensionsForFile.

src/cm/lsp/clientManager.ts — the formatDocument attach-without-aliases gap and the #resolveRootUri reorder are both in this file.

Important Files Changed

Filename Overview
src/cm/lsp/clientManager.ts Core change: adds #resolveDocumentUri, moves per-server URI resolution into the loop, introduces uriAliases map in #createClientState, and reorders #resolveRootUri priority. The formatDocument path still calls attach without aliases — inconsistent with getExtensionsForFile.
src/cm/lsp/types.ts Adds DocumentUriContext interface, documentUri hook to LspServerManifest and LspServerDefinition, updates rootUri to MaybePromise, and updates ClientState.attach signature. MaybePromise is defined but not exported.
src/cm/lsp/serverRegistry.ts Adds documentUri to sanitizeDefinition mirroring the existing rootUri pattern: only admitted if it is a function, otherwise stored as null.
src/cm/lsp/providerUtils.ts Threads documentUri through ManagedServerOptions and defineServer — straightforward plumbing, no logic changes.
src/cm/lsp/index.ts Adds DocumentUriContext to the public re-export list. Single-line change, no issues.

Sequence Diagram

sequenceDiagram
    participant EM as editorManager
    participant CM as LspClientManager
    participant RDU as resolveDocumentUri
    participant RRU as resolveRootUri
    participant CS as ClientState

    EM->>CM: getExtensionsForFile(metadata)
    loop for each matching server
        CM->>RDU: resolveDocumentUri(server, context)
        RDU->>RDU: normalizeDocumentUri(originalUri)
        alt normalizedUri is null
            RDU->>RDU: buildFileUri(file.cacheFile)
        end
        alt server.documentUri is function
            RDU->>RDU: await server.documentUri(originalUri, ctx+normalizedUri)
        end
        RDU-->>CM: normalizedUri (or null, skip server)
        CM->>RRU: resolveRootUri(server, context)
        Note over RRU: Priority: server.rootUri fn, context.rootUri, options.resolveRoot
        RRU-->>CM: rootUri
        CM->>CS: attach(normalizedUri, view, aliases=[originalUri])
        Note over CS: uriAliases: originalUri to normalizedUri
    end

    EM->>CM: detach(originalUri, view)
    CM->>CS: detach(originalUri, view)
    Note over CS: actualUri = uriAliases.get(originalUri) = normalizedUri
    CS->>CS: fileRefs.delete(normalizedUri)
    CS->>CS: cleanup uriAliases entries pointing to normalizedUri
    CS->>CS: workspace.closeFile(normalizedUri)
Loading

Comments Outside Diff (2)

  1. src/cm/lsp/clientManager.ts, line 355 (link)

    P2 formatDocument attach call is missing aliases

    formatDocument calls state.attach(normalizedUri, view) without passing aliases, whereas getExtensionsForFile (added in this PR) correctly passes [originalUri] when originalUri !== normalizedUri. Because editorManager.js calls lspClientManager.detach(uri) with the original (unnormalized) file URI (e.g. content://...), the alias lookup will miss this fileRefs entry and the file will never be properly closed via closeFile on the LSP workspace when using the formatting path.

    The fix would be to mirror the alias logic used in getExtensionsForFile:

    const aliases =
        originalUri && originalUri !== normalizedUri ? [originalUri] : [];
    state.attach(normalizedUri, view, aliases);
    

    This is a pre-existing gap in the formatting path, not a regression from this PR, but since the alias mechanism now exists it would be consistent to apply it here too.

  2. src/cm/lsp/clientManager.ts, line 906-930 (link)

    P2 #resolveRootUri priority reorder is a behavioural change

    Before this PR the resolution order was:

    1. context.rootUri (short-circuit — the caller always won)
    2. server.rootUri function
    3. options.resolveRoot function

    After this PR it is:

    1. server.rootUri function
    2. context.rootUri
    3. options.resolveRoot function

    This is the intentional fix for Codemirror LSP not using uri I passed #1996, but any existing plugin that sets context.rootUri to override the server's own rootUri function will now find that the server's function takes precedence. For correctness this is the right order — just worth documenting in changelog/upgrade notes so downstream plugin authors are aware.

Reviews (1): Last reviewed commit: "fix(lsp): allow plugins to override docu..." | Re-trigger Greptile

bajrangCoder added a commit to Acode-Foundation/acode-plugin-docs that referenced this pull request Mar 31, 2026
@bajrangCoder bajrangCoder merged commit d5fc8ce into Acode-Foundation:main Mar 31, 2026
5 checks passed
@bajrangCoder bajrangCoder deleted the lsp-plugin-uri-overrides branch March 31, 2026 08:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codemirror LSP not using uri I passed

1 participant